"""
-------------------------------
- File_Name: logs.py
- Date: 2025/2/17
- Author: yangzhide
- Email: xxzjyzd@126.com
- Description: 通用中间件
-------------------------------
"""
import json
import re
from config import get_api_environment_var
from fastapi.responses import JSONResponse
from starlette.types import ASGIApp, Receive, Scope, Send
from datetime import datetime
from json import JSONDecodeError
import orjson
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import Request
from app.core.bgtask import BgTasks
from app.models import APILog, MethodType
from app.core.security import get_current_user
from app.core.exceptions import AuthenticationError
from app.models.system.admin import User,Api
from app.logging.config import log


class SimpleBaseMiddleware:
    def __init__(self, app: ASGIApp) -> None:
        self.app = app

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        await self.handle_http(scope, receive, send)

    async def handle_http(self, scope, receive, send) -> None:
        request = Request(scope, receive)
        response = await self.before_request(request) or self.app

        async def send_wrapper(_response):
            await self.after_request(request, _response)
            await send(_response)

        await response(scope, receive, send_wrapper)

    async def before_request(self, request: Request) -> ASGIApp | None:
        ...

    async def after_request(self, request: Request, response: dict):
        ...
class BackGroundTaskMiddleware(SimpleBaseMiddleware):
    async def before_request(self, request: Request) -> ASGIApp | None:
        await BgTasks.init_bg_tasks_obj()
        # return self.app

    async def after_request(self, request: Request, response: dict) -> None:
        await BgTasks.execute_tasks()


class APILoggerMiddleware(BaseHTTPMiddleware):
    """记录接口日志到数据库"""

    async def dispatch(self, request: Request, call_next):
        try:
            request.state.start_time = datetime.now()
            user_obj: User | None = None
            api_obj: list | None = None
            token = request.headers.get("Authorization", None)
            # 用户
            if token and len(token) > 156:
                token = token.replace("Bearer ", "")
                user_obj: User = await get_current_user(token)
            try:
                # 匹配api管理
                api_environment = get_api_environment_var()
                version = api_environment.version
                match = re.search(f"{version}(.*?)(?:\?|$)", str(request.url))
                # 静态文件记录是空
                if match is not None:
                    target_path = str(match.group(1)) if match else None
                else:
                    target_path = ""
                method = getattr(MethodType, request.method.upper(), None)
                if re.search(r'/\d+$', target_path):
                    target_path = re.sub(r'(\d+)$', '{id}', target_path)
                api_obj = await Api.get_or_none(path=target_path, method=method).values("method","summary","tags")
                request_data = await request.json() if request.method in ["POST", "PUT", "PATCH"] else None
            except JSONDecodeError:
                request_data = None


            api_log_data = {
                "user_code": user_obj.user_code if user_obj else "system",
                "user_name": user_obj.user_name if user_obj else "system",
                "ip_address": request.client.host if request.client else "none",
                "request_url": str(request.url),
                "request_params": dict(request.query_params) or None,
                "request_data": request_data,
                "method": api_obj.get('method',"暂无") if api_obj else None ,
                "summary": api_obj.get('summary',"暂无介绍") if api_obj else None,
            }
            api_log_obj = await APILog.create(**api_log_data)
            # 绑定当前请求ID
            request.state.api_log_id = api_log_obj.id
            response = await call_next(request)
            return response
        except AuthenticationError as auth_err:
            # 认证异常，直接返回
            response_data = {
                "code": 401,
                "data": None,
                "msg": auth_err.detail,
            }
            return JSONResponse(status_code=200, content=response_data)
        except Exception as e:
            # 对于其他异常，抛出异常，让全局处理器处理
            raise e

class APILoggerAddResponseMiddleware(SimpleBaseMiddleware):
    """
    需要与APILoggerMiddleware搭配使用
    """

    async def after_request(self, request: Request, response: dict) -> None:
        from app.core.ctx import CTX_USER
        if hasattr(request.state, "api_log_id") and response.get("type") == "http.response.body":
            response_body = response.get("body", b"")
            try:
                resp = orjson.loads(response_body)
                api_log_obj = await APILog.get(id=request.state.api_log_id)
                if api_log_obj:
                    api_log_obj.user_name = CTX_USER.get().user_name if CTX_USER.get() else "system"
                    api_log_obj.user_code = CTX_USER.get().user_code if CTX_USER.get() else "system"
                    api_log_obj.response_data = resp
                    api_log_obj.response_code = resp.get("code", "-1")
                    api_log_obj.process_time = (datetime.now() - request.state.start_time).total_seconds()
                    await api_log_obj.save()
                    info_data = api_log_obj.user_name + resp.get("msg","None")
                    log.info(info_data)
            except orjson.JSONDecodeError:
                pass
